/**
 * @Description: 数据字典
 * @author 刘贵
 * @date 2021/04/16
 */

const errorCounts = {}
const sleepTimeOut = {}

let getRoute = function () {
  return '/'
}
/**
 * @description  字典管理
 * @description  未获取的字典数据会发送请求，已获取的字典多次添加不做任何操作
 */
export default context => ({
  namespaced: true,
  state: {
    // 存放字典集，以key为健存储
    dictionaries: {
      root: {},
      page: {}
    },
    // 缓存请求结果，以url|uri为健存储
    allDictRequestCache: {}
  },
  getters: {
    /**
     * 获取典数据字
     * @param state
     * @returns {Object}
     */
    dictionary (state) {
      const dataRoute = getRoute()
      const rootDict = state.dictionaries.root || {}
      const pageDict = state.dictionaries.page[dataRoute] || {}
      return Object.assign({}, rootDict, pageDict)
    }
  },
  actions: {
    resolveRoute (_, callback) {
      getRoute = callback
    },
    /**
     * @description 拉取字典数据
     * @param root 是否根级字典，默认添加到页面下
     * @param dictName 字典名称 （key)
     * @param dataSource 数据来源 url | uri
     * @param isGetAllDict 是否是获取所有字典对象， 如果是会循环处理，以key为dictName存储
     * @param dataKeys 返回结果的取值key集
     * @param callbacks 回调集， begin,end,complete
     * @returns {Promise<void>}
     */
    async pull ({ state, getters, dispatch, commit }, { root, dictName, dataSource, isGetAllDict, dataKeys = 'data', callbacks } = {}) {
      const request = state.allDictRequestCache[dataSource]
      const dictionary = root === true ? state.dictionaries.root : state.dictionaries.page[getRoute()]
      const requestResultIsUndefined = request === undefined || (request && request['dictData'] === undefined)

      if (
        (
          (dictName && dictionary[dictName] === undefined && requestResultIsUndefined) ||
          (isGetAllDict && requestResultIsUndefined)
        ) && dataSource
      ) {
        // 设置false值，防止意外情况短时间内连续多次请求同一个字典消耗资源
        if (dictName) { dictionary[dictName] = false }
        state.allDictRequestCache[dataSource] = false

        if (callbacks && callbacks.begin) { callbacks.begin() }

        clearTimeout(sleepTimeOut[dataSource])

        context.get(dataSource, {}, { alwaysReturnResolve: false, abortSameRequest: true, hideErrorToast: true })
          .then(resDictData => {
            const successData = { code: 'success' }
            if (callbacks && callbacks.end) { callbacks.end(successData) }
            resDictData = context.vm.prototype.$helper.get(resDictData, dataKeys) || undefined

            state.allDictRequestCache[dataSource] = {
              dictData: resDictData,
              dictName
            }
            dispatch('set', { root, dictName, dictData: resDictData, isGetAllDict, callbacks, callbackData: successData })
            errorCounts[dataSource] = 0
          })
          .catch((error) => {
            // TODO 错误处理
            // 请求出错后启动循环机制，间隔请求字典数据
            let errorData = { code: 'fail', loopComplete: true, loopCount: 0 }
            let sleepTime = errorCounts[dataSource] > 1 ? 15000 : 6000
            const isCancelRequest = !error.statusCode && error.errMsg === 'request:fail abort'
            // 如果错误是取消请求或服务器返回的状态码（有些接口没有数据也会返回错误）引起的，不启动循环机制
            if (!isCancelRequest && error.statusCode !== 200) {
              errorCounts[dataSource] += 1
              if (errorCounts[dataSource] <= 4) {
                errorData.loopComplete = false
                errorData.loopCount = errorCounts[dataSource]
                sleepTimeOut[dataSource] = setTimeout(() => {
                  dispatch('pull', { root, dictName, dataSource, isGetAllDict, dataKeys, callbacks })
                }, sleepTime)
              } else {
                errorData.loopCount = errorCounts[dataSource]
                errorCounts[dataSource] = 0
              }
            }

            // 重新复位对应数据为未请求过时的标志
            state.allDictRequestCache[dataSource] = undefined
            if (dictName) { dictionary[dictName] = undefined }

            if (callbacks && callbacks.end) { callbacks.end(errorData) }

            dispatch('set', { root, dictName, dictData: undefined, isGetAllDict, callbacks, callbackData: errorData })
            if (callbacks && callbacks.error) { callbacks.error(errorData) }
          })
      }
    },

    /**
     * @description 设置字典数据
     * @param root 是否根级字典，默认添加到页面下
     * @param dictName 字典名称（key）
     * @param dictData 字典数据
     * @param isGetAllDict 是否是获取所有字典对象， 如果是会循环处理，以key为dictName存储
     * @param callbacks 回调集， begin,end,complete
     */
    set ({ state }, { root, dictName, dictData, isGetAllDict, callbacks, callbackData } = {}) {
      if ((dictName || isGetAllDict)) {
        let dict = {}
        if (isGetAllDict && dictData) {
          for (const k in dictData) {
            dict[k] = dictData[k]
          }
        } else {
          dict[dictName] = dictData
        }
        if (root === true) {
          state.dictionaries.root = Object.assign({}, state.dictionaries.root, dict)
        } else {
          let route = getRoute()
          dict = {
            [route]: Object.assign({}, state.dictionaries.page[route] || {}, dict)
          }
          state.dictionaries.page = Object.assign({}, state.dictionaries.page, dict)
        }
        if (callbacks && callbacks.complete) { callbacks.complete(callbackData) }
        // TODO 更新字典了输出
        // console.log('----------字典------------')
        // console.log(state.dictionaries)
        // console.log('----------------------')
      }
    },

    /**
     * @description 清除请求缓存
     * @param state
     * @param {String} dictName
     */
    clearRequestCache ({ state }, { dictName = '' } = {}) {
      if (dictName && typeof (dictName) === 'string') {
        if (state.allDictRequestCache) {
          for (let key in state.allDictRequestCache) {
            const val = state.allDictRequestCache[key]
            if (val && val.dictName === dictName) {
              state.allDictRequestCache[key] = undefined
              break
            }
          }
        }
      }
    },

    /**
     * @description 删除字典值
     * @param state
     * @param root
     * @param dispatch
     * @param dictName
     */
    remove ({ state, dispatch }, { root, dictName = '' } = {}) {
      if (dictName && typeof (dictName) === 'string') {
        let route = getRoute()
        if (state.dictionaries.page[route]) {
          state.dictionaries.page[route][dictName] = undefined
        }
        if (root === true) {
          state.dictionaries.root[dictName] = undefined
        }
        dispatch('clearRequestCache', { dictName })
      }
    },

    /**
     * @description 替换字典值
     * @param dispatch
     * @param dictName
     * @param dictData
     * @param isGetAllDict
     * @param callbacks
     */
    replace ({ dispatch }, { root, dictName = '', dictData = undefined, isGetAllDict = false, callbacks } = {}) {
      if (dictName && typeof (dictName) === 'string') {
        dispatch('clearRequestCache', { dictName })
        dispatch('set', { root, dictName, dictData, isGetAllDict, callbacks })
      }
    },

    /**
     * @description 添加一个新的字段对象，如果该字典或请求字典数据url|uri已有缓存，则取缓存值
     * @description 参数可能存在的组合 { dictName, dictData },{ dictName, dataSource, [且isGetAllDict===false] }, { dataSource, isGetAllDict === true }
     * @param root 是否根级字典，默认添加到页面下
     * @param dictName 字典名称
     * @param dataSource 数据来源 url|uri
     * @param dictData 字典数据
     * @param isGetAllDict 是否是获取所有字典对象， 如果是会循环处理，以key为dictName存储
     * @param dataKeys 返回结果的取值key集
     * @param callbacks 回调集， begin,end,complete
     */
    push ({ state, dispatch }, { root, dictName = '', dataSource = '', dictData = null, isGetAllDict = false, dataKeys = 'data', callbacks } = {}) {
      let route
      if (root !== true) {
        route = getRoute()
        if (!state.dictionaries.page[route]) {
          state.dictionaries.page[route] = {}
        }
      }

      if (dictData) {
        dispatch('replace', { root, dictName, dictData, isGetAllDict, callbacks })
      } else {
        const dictCacheRequestItem = state.allDictRequestCache[dataSource]
        if (dictCacheRequestItem && dictCacheRequestItem.dictData) {
          dispatch('set', { root, dictName, dictData: dictCacheRequestItem.dictData, isGetAllDict, callbacks })
        } else {
          const dictKeyValue = root === true ? state.dictionaries.root[dictName] : state.dictionaries.page[route][dictName]
          // 值为undefined表示从未获取过，则远程拉取
          if (dictKeyValue === undefined) {
            if (errorCounts[dataSource] === undefined) {
              errorCounts[dataSource] = 0
            }
            if (sleepTimeOut[dataSource] === undefined) {
              sleepTimeOut[dataSource] = 0
            }
            dispatch('pull', { root, dictName, dataSource, isGetAllDict, dataKeys, callbacks })
          } else {
            if (callbacks && callbacks.complete) { callbacks.complete() }
          }
        }
      }
    }
  },
  mutations: {

  }
})
